#pragma once
#include "tracker.h"
class CAngleRect :
  public CTracker
{
protected:
  // Hit-Test codes
  enum TrackerHit
  {
    kHitNothing = -1,
    kHitEast = 0, kHitNorthEast = 1, kHitNorth = 2, kHitNorthWest = 3,
    kHitWest = 4, kHitSouthWest = 5, kHitSouth = 6, kHitSouthEast = 7,
    kHitTop = 8, kHitBottom = 9, kHitLeft = 10, kHitRight = 11,
    kHitMiddle = 12, kHitButt
  };

  // Keystroke-Test codes
  enum KeyStroke
  {
    kStrokeNothing = -1,
    kStrokeLineUp = 0, kStrokeLineDown = 1, kStrokeLineLeft = 2,
    kStrokeLineRight = 3, kStrokePageUp = 4, kStrokePageDown = 5,
    kStrokePageLeft = 6, kStrokePageRight = 7, kStrokeButt
  };

public:
  struct AngleRect {
    double x;
    double y;
    double width;
    double height;
    double angle;
  };

public:
  CAngleRect(double x, double y, double width, double height, double angle);
  ~CAngleRect(void);

public:
  void LeftButtonDown_slot(CWnd* sender, const MouseArgument& arg);
  void LeftButtonUp_slot(CWnd* sender, const MouseArgument& arg);
  void MouseMove_slot(CWnd* sender, const MouseArgument& arg);
  bool CursorSet_slot(CWnd* sender, const MouseArgument& arg);

public:
  void Draw(Hlong halcon_wnd_handle);
  void AdjustHandles(void);

public:
  AngleRect angle_rect(void) const { return angle_rect_; }
  void set_angle_rect(const AngleRect &angle_rect)
  {
    angle_rect_ = angle_rect;
    Rotate();
    AdjustHandles();
  }

public:
  static double TrackAll(const geometry::Point2D& vertex0,
    const geometry::Point2D& vertex1, double length0,
    geometry::Point2D& vertex3, geometry::Point2D& vertex2,
    double length1, const geometry::Point2D& pt);

  static bool IsAcute(const geometry::Point2D &v, const geometry::Point2D &w)
  {
    return v.x()*w.x()+v.y()*w.y() > 0;
  }

  static bool IsAcute(const geometry::Point2D &b, const geometry::Point2D &p0,
    const geometry::Point2D &p1)
  { 
    geometry::Point2D v(p0.x()-b.x(), p0.y()-b.y());
    geometry::Point2D w(p1.x()-b.x(), p1.y()-b.y());

    return IsAcute(v, w);
  }

  static double Distance(const geometry::Point2D &vertex0,
    const geometry::Point2D &vertex1, double length,
    const geometry::Point2D & pt)
  {
    if(length != 0) {
      return fabs(((vertex0.y()-vertex1.y())*pt.x()+(vertex1.x()-vertex0.x())*pt.y()+
        (vertex0.x()*vertex1.y()-vertex1.x()*vertex0.y()))/length);
    }

    return sqrt((pt.x()-vertex0.x())*(pt.x()-vertex0.x())+
      (pt.y()-vertex0.y())*(pt.y()-vertex0.y()));
  }

private:
  void Rotate(void);
  bool CursorOn(const geometry::Point2D &point) const;
  bool PtInside(const geometry::Point2D &point) const;
  bool PtOnAngleRect(const geometry::Point2D &point) const;
  void HitTest(const geometry::Point2D& point);
  void TrackTo(const geometry::Point2D& point);

  void TrackEast(const geometry::Point2D& pt)
  { 
    angle_rect_.width = TrackAll(vertexes_[0], vertexes_[1], angle_rect_.height,
      vertexes_[3], vertexes_[2], angle_rect_.width, pt);
  }

  void TrackNorth(const geometry::Point2D& pt)
  { 
    angle_rect_.height = TrackAll(vertexes_[1], vertexes_[2], angle_rect_.width,
      vertexes_[0], vertexes_[3], angle_rect_.height, pt);
  }

  void TrackWest(const geometry::Point2D& pt)
  { 
    angle_rect_.width = TrackAll(vertexes_[2], vertexes_[3], angle_rect_.height,
      vertexes_[1], vertexes_[0], angle_rect_.width, pt);
  }

  void TrackSouth(const geometry::Point2D& pt)
  { 
    angle_rect_.height = TrackAll(vertexes_[3], vertexes_[0], angle_rect_.width,
      vertexes_[2], vertexes_[1], angle_rect_.height, pt);
  }

private:
  AngleRect         angle_rect_;
  geometry::Point2D vertexes_[4];
  geometry::Rect2D  handles_[8];
  TrackerHit        hit_code_;
};

